package com.example.chatroom.service.impl;

import com.example.chatroom.common.errorcode.ServiceErrorCodeConstants;
import com.example.chatroom.common.exception.ServiceException;
import com.example.chatroom.common.utils.DigesterUtils;
import com.example.chatroom.common.utils.JWTUtil;
import com.example.chatroom.common.utils.RedisUtil;
import com.example.chatroom.common.utils.UUIDUtil;
import com.example.chatroom.controller.param.UserParam;
import com.example.chatroom.dao.dataobject.UserDO;
import com.example.chatroom.dao.mapper.UserMapper;
import com.example.chatroom.service.IUserService;
import com.example.chatroom.service.dto.UserDTO;
import io.jsonwebtoken.Claims;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.lang.invoke.VarHandle;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

@Slf4j
@Service
public class UserServiceImpl implements IUserService {
    @Autowired
    private UserMapper userMapper;
    @Autowired
    private DigesterUtils digesterUtils;
    @Autowired
    private UUIDUtil uuidUtil;
    @Autowired
    private JWTUtil jwtUtil;
    @Autowired
    private RedisUtil redisUtil;
    @Override
    public UserDTO login(UserParam userParam) {
        UserDO userDO=userMapper.selectByUserName(userParam.getUserName());
        if(userDO==null){
            log.error(ServiceErrorCodeConstants.USER_NOT_EXIST_ERROR.getMsg());
            throw new ServiceException(ServiceErrorCodeConstants.USER_NOT_EXIST_ERROR);
        }
        //密码取出后校验
        boolean verify = digesterUtils.verify(userParam.getPassword(), userDO.getPassword(),userDO.getSalt());
        if(verify==false){
            log.error(ServiceErrorCodeConstants.USER_PASSWORD_ERROR.getMsg());
            throw new ServiceException(ServiceErrorCodeConstants.USER_PASSWORD_ERROR);
        }
        //校验成功后返回令牌给前端
        Map<String,Object> map=new HashMap<>();
        map.put("userId",userDO.getId());
        map.put("userName",userDO.getUserName());
        String jwtToken = jwtUtil.genToken(map);
        //构造返回值
        UserDTO userDTO =new UserDTO();
        userDTO.setUserToken(jwtToken);
        userDTO.setId(userDO.getId());
        userDTO.setGmtCreate(userDO.getGmtCreate());
        userDTO.setGmtModified(userDO.getGmtModified());
        userDTO.setUserName(userDO.getUserName());
        return userDTO;
    }

    @Override
    public UserDTO register(UserParam userParam) {
        //1-    判断用户是否存在，如果已经存在就不能注册了
        if(userMapper.selectByUserName(userParam.getUserName())!=null){
            log.error(ServiceErrorCodeConstants.USER_USER_NAME_EXISTS.getMsg());
            throw new ServiceException(ServiceErrorCodeConstants.USER_USER_NAME_EXISTS);
        }
        //2-    插入数据,插入密码前需要加密
        UserDO userDO=new UserDO();
        userDO.setUserName(userParam.getUserName());
        //生成盐
        String salt = uuidUtil.getUUID();
        userDO.setSalt(salt);
        //加密后插入
        userDO.setPassword(digesterUtils.encrypt(userParam.getPassword(), salt));
        userMapper.insertSelective(userDO);
        //构造返回值
        UserDTO userDTO =new UserDTO();
        userDTO.setId(userDO.getId());
        userDTO.setGmtCreate(userDO.getGmtCreate());
        userDTO.setGmtModified(userDO.getGmtModified());
        userDTO.setUserName(userDO.getUserName());
        return userDTO;
    }

    /**
     * 注销用户
     * @return
     */
    @Override
    public void exit(HttpServletRequest request) {
        //1-    判断user_token是否存在
        String userToken=request.getHeader("user_token");
        if(!StringUtils.hasLength(userToken)){
            log.info(ServiceErrorCodeConstants.USER_TOKEN_NOT_EXISTS.getMsg());
            throw new ServiceException(ServiceErrorCodeConstants.USER_TOKEN_NOT_EXISTS);
        }
        //2-    校验令牌是否合法
        Claims verify = jwtUtil.verify(userToken);
        if(verify==null){
            log.error("Token非法 user_token:{}",userToken);
            throw new ServiceException(ServiceErrorCodeConstants.USER_TOKEN_UNLAWFUL);
        }
        //3-    获取token的id，唯一表示一个令牌
        String id = verify.getId();
        // 获取过期时间戳（毫秒）
        long expirationTimestamp = verify.getExpiration().getTime();
        // 计算剩余有效时间（秒）
        long ttlMillis = (expirationTimestamp - System.currentTimeMillis())/1000;
        if (ttlMillis > 0) {
            //4-    将当前的userToken设置为黑名单
            if(redisUtil.set("BlackToken:" + id, "invalid", ttlMillis)==false){
                log.error("exit  userTokenId:{} redis缓存黑名单失败",id);
                throw new ServiceException(ServiceErrorCodeConstants.USER_BLACK_TOKEN_REDIS_ERROR);
            }
        }
    }

    @Override
    public UserDTO getUserInfo(HttpServletRequest request) {
        //1-    判断user_token是否存在
        String userToken=request.getHeader("user_token");
        if(!StringUtils.hasLength(userToken)){
            log.info(ServiceErrorCodeConstants.USER_TOKEN_NOT_EXISTS.getMsg());
            throw new ServiceException(ServiceErrorCodeConstants.USER_TOKEN_NOT_EXISTS);
        }
        //2-    校验令牌是否合法
        Claims verify = jwtUtil.verify(userToken);
        if(verify==null){
            log.error("Token非法 user_token:{}",userToken);
            throw new ServiceException(ServiceErrorCodeConstants.USER_TOKEN_UNLAWFUL);
        }
        Map<String, Object> tokenInfo = jwtUtil.getTokenInfo(userToken);
        UserDTO userDTO =new UserDTO();
        Long userId = jwtUtil.getUserId(userToken);
        userDTO.setId(userId);
        userDTO.setUserName((String)tokenInfo.get("userName"));
        return userDTO;
    }


}
